#pragma once
#include <string>


namespace {
	const int MAX_YEAR = 9999;
	const int MIN_YEAR = 1;
	const int MAX_MONTH = 12;
	const int MIN_MONTH = 1;
	const int MIN_DAY = 1;
	const int MAX_HOUR = 23;
	const int MIN_HOUR = 0;
	const int MAX_MINUTE = 59;
	const int MIN_MINUTE = 0;
	const int MAX_SECOND = 59;
	const int MIN_SECOND = 0;

	const int NULL_VALUE = 0;
	const int SIZE_BUFFER = 25;
	const int SIZE_YEAR = 5;
	const int SIZE_DAY = 3;
	const int SIZE_HOUR = 3;
	const int SIZE_MONTH = 4;
	const int SIZE_MINUTE = 3;
	const int SIZE_SECOND = 3;
	const std::string YEAR_FORMAT("YYYY");
	const std::string MONTH_FORMAT("MMM");
	const std::string DAY_FORMAT("DD");
	const std::string HOUR_FORMAT("hh");
	const std::string MINUTE_FORMAT("mm");
	const std::string SECOND_FORMAT("ss");

	const int ERROR = 0;
	const int FIRST_MONTH = 1;
}

class DateInterval;

class Date
{
	public:
		enum Months {Jan=::FIRST_MONTH, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};

private:
	unsigned int year;
	Months month;
	unsigned int day;
	unsigned int hour;
	unsigned int minute;
	unsigned int second;
	
public:
	
	Date();
	Date(const unsigned int year, const Months month, const unsigned int day);
	Date(const unsigned int hour, const unsigned int minute, const unsigned int second);
	Date(const unsigned int year, const Months month, const unsigned int day, const unsigned int hour,
		 unsigned int minute, const unsigned int second);

	Date addYear(const int year) const;
	Date addMonth(const int month) const;
	Date addDay(const int day) const;
	Date addHour(const int hour) const;
	Date addMinute(const int minute) const;
	Date addSecond(const int second) const;

	unsigned int getYear() const;
	Months getMonth() const;
	unsigned int getDay() const;
	unsigned int getHour() const;
	unsigned int getMinute() const;
	unsigned int getSecond() const;
	
	std::string toString() const;
	std::string formatDate(const std::string format) const;

	DateInterval getInterval(const Date& another) const;
	Date addInterval(const DateInterval& interval) const;

private:
	void buildYear( const unsigned int year );
	void buildMonth( const Months month );
	int buildDay( const unsigned int day, const Months month, const unsigned int year );
	void buildHour( const unsigned int hour );
	void buildMinutes( unsigned int minute );
	void buildSecons( const unsigned int second );

public:
	static bool isLeapYear (const unsigned int year);
	static unsigned int getDaysInMonth (Months month, bool isYearLeap);
private:
	static const unsigned int numberDays[::MAX_MONTH];
	static const char* const strMonth[::MAX_MONTH];
};

class DateInterval 
{

public:
	DateInterval(int yearDiff, int mouthDiff, int dayDiff, int hourDiff, int minuteDiff, int secondDiff);

	int getYearDifference() const;
	int getMonthDifference() const;
	int getDayDifference() const;
	int getHourDifference() const;
	int getMinuteDifference() const;
	int getSecondDifference() const;
	
private:
	int year;
	int month;
	int day;
	int hour;
	int minute;
	int second;
};


class DateIntervalBuilder
{
public:
	DateIntervalBuilder();
	DateIntervalBuilder& setYear(int year);
	DateIntervalBuilder& setMonth(int month);
	DateIntervalBuilder& setDay(int day);
	DateIntervalBuilder& setHour(int hour);
	DateIntervalBuilder& setMinute(int minute);
	DateIntervalBuilder& setSecond(int second);

	DateInterval build() const;

private:
	int year;
	int month;
	int day;
	int hour;
	int minute;
	int second;
};


